package com.tupu.service.impl.dispatch;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.deepoove.poi.XWPFTemplate;
import com.tupu.common.PageResult;
import com.tupu.entity.dispatch.PlanText;
import com.tupu.entity.dispatch.WarningEventFailurePlan;
import com.tupu.entity.dto.WarningEventFailurePlanDto;
import com.tupu.entity.neo4j.NodeSingle;
import com.tupu.mapper.dispatch.WarningEventFailurePlanMapper;
import com.tupu.service.dispatch.PlanService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import org.wltea.analyzer.core.IKSegmenter;
import org.wltea.analyzer.core.Lexeme;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class PlanServiceImpl implements PlanService {

    @Autowired(required = false)
    private WarningEventFailurePlanMapper warningEventFailurePlanMapper;

    @Override
    public void del(String planId) {
        warningEventFailurePlanMapper.deleteById(planId);
    }

    @Override
    public void downloadWordTemplate(HttpServletResponse response) {
        InputStream inputStream = null;
        OutputStream fileOut = null;
        try {
            inputStream = new ClassPathResource("/template/基准风险预案模板.docx").getInputStream();
            String fileName = new String("基准风险预案模板".getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);
            response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".docx");
            response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
            fileOut = response.getOutputStream();

            //循环写入输出流
            byte[] b = new byte[2048];
            int length;
            while ((length = inputStream.read(b)) > 0) {
                fileOut.write(b, 0, length);
            }
            inputStream.close();
            fileOut.close();
        } catch (Exception e) {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException ioException) {
                    ioException.printStackTrace();
                }
            }

            if (fileOut != null) {
                try {
                    fileOut.close();
                } catch (IOException ioException) {
                    ioException.printStackTrace();
                }
            }
            e.printStackTrace();
            throw new RuntimeException("模板下载出错!");
        }
    }

    @Override
    public void importWord(MultipartFile file) throws Exception {
        //String type = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
        //if (type.equals(".docx")) {
        String filename = file.getOriginalFilename();
        String[] fileNames = filename.split("\\.");
        //创造临时文件，方法结束后删除
        File newFile = File.createTempFile(fileNames[0], "." + fileNames[1]);
        InputStream inputStream = file.getInputStream();
        FileUtils.copyInputStreamToFile(inputStream, newFile);
        String absolutePath = newFile.getAbsolutePath();

        FileInputStream in = new FileInputStream(absolutePath);//载入文档
        // 处理docx格式 即office2007以后版本
        //word 2007 图片不会被读取， 表格中的数据会被放在字符串的最后
        XWPFDocument xwpf = new XWPFDocument(in);//得到word文档的信息
        Iterator<XWPFTable> it = xwpf.getTablesIterator();//得到word中的表格
        int tableCount = 0;
        for (XWPFTable table : xwpf.getTables()) {
            tableCount++;
        }
        System.out.println("表格总数：" + tableCount);
        while (it.hasNext()) {
            Map<String, Object> map = new HashMap<>();
            XWPFTable table = it.next();
            List<XWPFTableRow> rows = table.getRows();
            //读取每一行数据
            for (int i = 0; i < rows.size(); i++) {
                XWPFTableRow row = rows.get(i);
                //读取每一列数据
                List<XWPFTableCell> cells = row.getTableCells();
                String key1 = null;
                String key2 = "";
                String key3 = "";
                String key4;
                String key5 = "";

                String value1 = "";
                String value2 = "";
                String value3 = "";
                String value5 = "";

                for (int j = 0; j < cells.size(); j++) {
                    XWPFTableCell cell = cells.get(j);
                    if (cells.size() == 2) {
                        if (j == 0) {
                            key1 = cell.getText();
                        } else {
                            value1 = cell.getText().trim();
                        }
                    }

                    if (cells.size() == 4) {
                        if (j == 0) {
                            key2 = cell.getText();
                        } else if (j == 1) {
                            value2 = cell.getText().trim();
                        }
                        if (j == 2) {
                            key3 = cell.getText();
                        } else if (j == 3) {
                            value3 = cell.getText().trim();
                        }
                    }

                    if (cells.size() == 3) {
                        if (j == 1) {
                            key4 = cell.getText();
                            if (key4.equals("南网总调") || key4.equals("广东中调") || key4.equals("茂名调控")) {
                                key5 = "主要控制目标" + "/" + key4;
                            }
                            if (key4.equals("上报单位") || key4.equals("上报对象") || key4.equals("上报内容")) {
                                key5 = "事故信息上报" + "/" + key4;
                            }
                            if (key4.equals("发布单位") || key4.equals("发布对象") || key4.equals("发布内容")) {
                                key5 = "事故信息发布" + "/" + key4;
                            }
                        } else if (j == 2) {
                            value5 = cell.getText();
                        }
                    }
                }
                map.put(key1, value1);
                map.put(key2, value2);
                map.put(key3, value3);
                map.put(key5, value5);
                map.remove(null);
                map.remove("");
            }
            NodeSingle node = new NodeSingle();
            node.setAttrs(map);
            WarningEventFailurePlan plan = new WarningEventFailurePlan();
            Map<String, Object> attrs = node.getAttrs();
            String name = null;
            //String number = null;
            if (attrs.containsKey("事故预案名称")) {
                name = attrs.get("事故预案名称").toString();
            }
            plan.setName(name);
            for (String s : attrs.keySet()) {
                if (s.contains("编号")) {
                    plan.setNumber(attrs.get(s).toString());
                }
            }
            if (attrs.containsKey("负责单位")) {
                plan.setPlace(attrs.get("负责单位").toString());
            }
            if (attrs.containsKey("创建日期")) {
                plan.setCreateDate(attrs.get("创建日期").toString());
            }
            if (attrs.containsKey("编制人")) {
                plan.setProducer(attrs.get("编制人").toString());
            }
            if (attrs.containsKey("审核人")) {
                plan.setAuditor(attrs.get("审核人").toString());
            }
            if (attrs.containsKey("概述")) {
                plan.setSummary(attrs.get("概述").toString());
            }
            if (attrs.containsKey("事前运行方式")) {
                plan.setBeforeWay(attrs.get("事前运行方式").toString());
            }
            if (attrs.containsKey("故障设置")) {
                plan.setFaultSetting(attrs.get("故障设置").toString());
            }
            if (attrs.containsKey("事后运行方式")) {
                plan.setAfterWay(attrs.get("事后运行方式").toString());
            }
            if (attrs.containsKey("事后风险分析")) {
                plan.setAfterRisk(attrs.get("事后风险分析").toString());
            }
            if (attrs.containsKey("主要控制目标/南网总调")) {
                plan.setTotalNote(attrs.get("主要控制目标/南网总调").toString());
            }
            if (attrs.containsKey("主要控制目标/广东中调")) {
                plan.setMiddleNote(attrs.get("主要控制目标/广东中调").toString());
            }
            if (attrs.containsKey("主要控制目标/茂名调控")) {
                plan.setRegulation(attrs.get("主要控制目标/茂名调控").toString());
            }
            if (attrs.containsKey("事故处理过程及要点")) {
                plan.setProcess(attrs.get("事故处理过程及要点").toString());
            }
            if (attrs.containsKey("事故信息上报/上报单位")) {
                plan.setReportedPlace(attrs.get("事故信息上报/上报单位").toString());
            }
            if (attrs.containsKey("事故信息上报/上报内容")) {
                plan.setReportedObject(attrs.get("事故信息上报/上报内容").toString());
            }
            if (attrs.containsKey("事故信息上报/上报对象")) {
                plan.setReportedContent(attrs.get("事故信息上报/上报对象").toString());
            }
            if (attrs.containsKey("事故信息发布/发布单位")) {
                plan.setPublishPlace(attrs.get("事故信息发布/发布单位").toString());
            }
            if (attrs.containsKey("事故信息发布/发布内容")) {
                plan.setPublishObject(attrs.get("事故信息发布/发布内容").toString());
            }
            if (attrs.containsKey("事故信息发布/发布对象")) {
                plan.setPublishContent(attrs.get("事故信息发布/发布对象").toString());
            }
            if (attrs.containsKey("事故影响评估")) {
                plan.setAssess(attrs.get("事故影响评估").toString());
            }
            if (attrs.containsKey("备注")) {
                plan.setRemarks(attrs.get("备注").toString());
            }
            //类别
            if (name.contains("母线")) {
                plan.setCategory(2);
            }
            if (name.contains("全站")) {
                plan.setCategory(1);
            } else {
                plan.setCategory(3);
            }
            //级别
            String number = plan.getNumber();
            if (number.contains("较大")) {
                plan.setLevel(6);
            }
            if (number.contains("一般")) {
                plan.setLevel(7);
            }
            if (number.contains("一级")) {
                plan.setLevel(1);
            }
            if (number.contains("二级")) {
                plan.setLevel(2);
            }
            if (number.contains("三级")) {
                plan.setLevel(3);
            }
            if (number.contains("四级")) {
                plan.setLevel(4);
            }
            if (number.contains("五级")) {
                plan.setLevel(5);
            }

            //更新时间
            Date date = new Date();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String time = sdf.format(date);
            plan.setUpdateTime(time);
            //厂站 分词
            StringReader reader = new StringReader(name);
            IKSegmenter ik = new IKSegmenter(reader, true);
            Lexeme lex;
            while ((lex = ik.next()) != null) {
                String text = lex.getLexemeText();
                if (text.contains("站") && !text.equals("全站")) {
                    plan.setStation(text);
                }
            }
            //不入预案库
            plan.setStateId(0);
            warningEventFailurePlanMapper.insert(plan);
        }
    }

    @Override
    public WarningEventFailurePlan findPlanByPlanId(Integer planId) {
        WarningEventFailurePlan plan = warningEventFailurePlanMapper.selectById(planId);
        return plan;
    }

    @Override
    public PageResult<WarningEventFailurePlanDto> conditionSearch(Integer pageNum, Integer pageSize, String planName, String device, String station, Integer category, Integer level) {
        QueryWrapper<WarningEventFailurePlan> wrapper = new QueryWrapper<>();
        Page<WarningEventFailurePlan> pageInfo = new Page<>(pageNum, pageSize);
        if (StringUtils.isNotEmpty(planName)) {
            wrapper.like("name", planName);
        }
        if (StringUtils.isNotEmpty(device)) {
            wrapper.like("device", device);
        }
        if (StringUtils.isNotEmpty(station)) {
            wrapper.eq("station", station);
        }
        if (category != null) {
            wrapper.eq("category", category);
        }
        if (level != null) {
            wrapper.eq("level", level);
        }

        wrapper.eq("state_id", 0);

        //wrapper.orderByDesc("create_date");
        Page<WarningEventFailurePlan> page = warningEventFailurePlanMapper.selectPage(pageInfo, wrapper);
        List<WarningEventFailurePlanDto> dtoList = new ArrayList<>();
        List<WarningEventFailurePlan> plans = page.getRecords();
        if (CollectionUtils.isNotEmpty(plans)) {
            for (WarningEventFailurePlan plan : plans) {
                WarningEventFailurePlanDto dto = new WarningEventFailurePlanDto();
                dto.setPlanId(plan.getPlanId());
                dto.setPlanName(plan.getName());
                dto.setDevice(plan.getDevice());
                dto.setStation(plan.getStation());
                dto.setCreateName(plan.getProducer());
                dto.setUpdateTime(plan.getUpdateTime());
                Integer cate = plan.getCategory();
                if (null != cate) {
                    if (cate == 1) {
                        dto.setCategory("站点");
                    }
                    if (cate == 2) {
                        dto.setCategory("母线");
                    }
                    if (cate == 3) {
                        dto.setCategory("线路");
                    }
                }
                Integer lev = plan.getLevel();
                if (null != lev) {
                    if (lev == 1) {
                        dto.setLevel("一级");
                    }
                    if (lev == 2) {
                        dto.setLevel("二级");
                    }
                    if (lev == 3) {
                        dto.setLevel("三级");
                    }
                    if (lev == 4) {
                        dto.setLevel("四级");
                    }
                    if (lev == 5) {
                        dto.setLevel("五级");
                    }
                    if (lev == 6) {
                        dto.setLevel("重大");
                    }
                    if (lev == 7) {
                        dto.setLevel("一般");
                    }
                }
                dtoList.add(dto);
            }
        }
        List<WarningEventFailurePlanDto> list = dtoList.stream().skip((pageNum - 1) * pageSize).limit(pageSize).collect(Collectors.toList());
        //排序
        list.sort(Comparator.comparing(WarningEventFailurePlanDto::getUpdateTime).reversed());
        PageResult<WarningEventFailurePlanDto> result = new PageResult<>();
        long total = page.getTotal();
        result.setTotal(total);
        result.setList(list);
        result.setPage(Long.valueOf(pageNum));
        result.setSize(Long.valueOf(pageSize));
        result.setTotalPages(Long.valueOf((total / pageSize + (total % pageSize != 0 ? 1 : 0))));
        return result;
    }

    @Override
    public void downloadWordByPlanId(Integer planId, HttpServletResponse response) throws IOException {

        String path = "/home/csv/基准风险预案模板导出.docx";

        WarningEventFailurePlan plan = warningEventFailurePlanMapper.selectById(planId);

        Map<String, Object> map = new HashMap<>();
        String name = plan.getName();
        map.put("name", name);//名称
        map.put("number", plan.getNumber());//编号
        map.put("place", plan.getPlace());//负责单位
        map.put("create_date", plan.getCreateDate());//创建日期
        map.put("producer", plan.getProducer());//编制人
        map.put("auditor", plan.getAuditor());//审核人
        map.put("summary", plan.getSummary());//概述
        map.put("before_way", plan.getBeforeWay());//事前运行方式
        map.put("fault_setting", plan.getFaultSetting());//故障设置
        map.put("after_way", plan.getAfterWay());//事后运行方式
        map.put("after_risk", plan.getAfterRisk());//事后风险分析
        map.put("total_note", plan.getTotalNote());//南网总调
        map.put("middle_note", plan.getMiddleNote());//广东中调
        map.put("regulation", plan.getRegulation());//茂名调控
        map.put("process", plan.getProcess());//事故处理过程及要点
        map.put("reported_place", plan.getReportedPlace());//上报单位
        map.put("reported_object", plan.getReportedObject());//上报对象
        map.put("reported_content", plan.getReportedContent());//上报内容
        map.put("publish_place", plan.getPublishPlace());//发布单位
        map.put("publish_object", plan.getPublishObject());//发布对象
        map.put("publish_content", plan.getPublishContent());//发布内容
        map.put("assess", plan.getAssess());//事故影响评估
        map.put("remarks", plan.getRemarks());//备注

        XWPFTemplate template = XWPFTemplate.compile(path).render(map);
        long time = System.currentTimeMillis();
        String fileName = time + ".docx";
        String file_path = "/home/csv/" + fileName;
        FileOutputStream fos = new FileOutputStream(file_path);
        template.write(fos);
        fos.flush();
        fos.close();
        template.close();

        File file = new File(file_path);
        FileInputStream fis = new FileInputStream(file);
        response.setContentType("application/octet-stream");
        response.setHeader("Content-Disposition", "attachment;filename=" + file.getName());
        BufferedInputStream bis = new BufferedInputStream(fis);
        ServletOutputStream sos = response.getOutputStream();
        byte[] buffer = new byte[1024];
        int len;
        while ((len = bis.read(buffer)) != -1) {
            sos.write(buffer, 0, len);
        }
        sos.flush();
        sos.close();
        bis.close();
        fis.close();
    }

    @Override
    public void updatePlanById(WarningEventFailurePlan plan) {
        //更新时间
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String time = sdf.format(date);
        plan.setUpdateTime(time);
        warningEventFailurePlanMapper.updateById(plan);
    }

    @Override
    public void insertPlan(WarningEventFailurePlan plan) {
        //更新时间
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String time = sdf.format(date);
        plan.setUpdateTime(time);
        plan.setStateId(0);
        plan.setPlanId(null);
        warningEventFailurePlanMapper.insert(plan);
        //neo4jUtil.addFailurePlan(plan);
    }

    @Override
    public void copyPlanByPlanId(Integer planId) {
        WarningEventFailurePlan plan = warningEventFailurePlanMapper.selectById(planId);
        plan.setPlanId(null);
        //更新时间
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String time = sdf.format(date);
        plan.setUpdateTime(time);
        warningEventFailurePlanMapper.insert(plan);
    }

    @Override
    public boolean textReplace(PlanText text) throws IllegalAccessException {
        Integer planId = text.getPlanId();
        String oldText = text.getOldText();
        String newText = text.getNewText();
        WarningEventFailurePlan plan = warningEventFailurePlanMapper.selectById(planId);
        boolean b = containsStringInEntity(plan, oldText);
        if (b) {
            replaceStringInEntity(plan, oldText, newText);
            //更新时间
            Date date = new Date();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String time = sdf.format(date);
            plan.setUpdateTime(time);
            warningEventFailurePlanMapper.updateById(plan);
            return true;
        } else {
            return false;
        }
    }

    private static boolean containsStringInEntity(Object entity, String oldStr) {
        Class<?> clazz = entity.getClass();
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            if (field.getType() == String.class) {
                field.setAccessible(true);
                try {
                    String value = (String) field.get(entity);
                    if (value != null && value.contains(oldStr)) {
                        return true;
                    }
                } catch (IllegalAccessException e) {
                    throw new RuntimeException("Failed to check if string is contained in entity fields: " + entity, e);
                }
            }
        }
        return false;
    }

    /**
     * 替换实体类中所有指定字符串
     *
     * @param entity
     * @param oldStr
     * @param newStr
     * @throws IllegalAccessException
     */
    public static void replaceStringInEntity(Object entity, String oldStr, String newStr) throws IllegalAccessException {
        Field[] fields = entity.getClass().getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            Object value = field.get(entity);
            if (value != null && value instanceof String) {
                String currentValue = (String) value;
                if (currentValue.contains(oldStr)) {
                    String replacedValue = currentValue.replace(oldStr, newStr);
                    field.set(entity, replacedValue);
                }
            }
        }
    }

    @Override
    public void testAddStation() {
        QueryWrapper<WarningEventFailurePlan> wrapper = new QueryWrapper<>();
        wrapper.isNull("station");
        List<WarningEventFailurePlan> planList = warningEventFailurePlanMapper.selectList(wrapper);
        try {
            for (WarningEventFailurePlan plan : planList) {
                String name = plan.getName();
                StringReader reader = new StringReader(name);
                IKSegmenter ik = new IKSegmenter(reader, true);
                Lexeme lex;
                while ((lex = ik.next()) != null) {
                    String text = lex.getLexemeText();
                    if (text.contains("站") && !text.equals("全站")) {
                        plan.setStation(text);
                        warningEventFailurePlanMapper.updateById(plan);
                    }
                }
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

}
